package main

import "log"

// 任务
type task struct {
	num      int
	interval int
	begin    int
	end      int
	result   chan<- int
}

// 工作池数量
const NUMBER = 10

// 计算bengin到end之和
// 并把结果放入result chan中去
func (t task) do() {
	sum := 0
	for i := t.begin; i <= t.end; i++ {
		sum += i
	}
	log.Printf("开始计算，%d-%d 结果=%d\n", t.begin, t.end, sum)
	t.result <- sum
}

func main() {
	worksNum := NUMBER
	// 任务通道
	taskChan := make(chan task, 10)
	// 结果通道
	resultChan := make(chan int, 10)

	done := make(chan struct{}, 10)

	// 生成任务
	go initTask(taskChan, resultChan, 100, 10)

	// 消费任务
	distask(taskChan, done, worksNum)

	// 关闭通道
	go closeResultChan(resultChan, done, worksNum)

	// 得到结果
	num := processResult(resultChan)

	log.Println("总数=", num)
}

// 初始化任务task
func initTask(taskChan chan<- task, resuChan chan<- int, num, interval int) {
	cishu := num / interval
	residueNum := num % interval
	// 处理可以整除的数据
	for i := 0; i < cishu; i++ {
		begin := interval*i + 1
		end := interval * (i + 1)
		t := task{
			num:      num,
			interval: interval,
			begin:    begin,
			end:      end,
			result:   resuChan,
		}

		taskChan <- t
	}

	// 分割剩余数量范围
	if residueNum != 0 {
		t := task{
			num:      num,
			interval: interval,
			begin:    num*cishu + 1,
			end:      num,
			result:   resuChan,
		}

		taskChan <- t
	}

	// 关闭
	defer close(taskChan)
}

// 分发任务
func distask(taskChan <-chan task, done chan struct{}, worksNum int) {
	for i := 0; i < worksNum; i++ {
		go processTask(taskChan, done)
	}
}

// 计算任务
func processTask(taskChan <-chan task, done chan struct{}) {
	for v := range taskChan {
		v.do()
	}

	// 通知已经计算完了
	done <- struct{}{}
}

// 读取结果
func processResult(resuChan <-chan int) int {
	num := 0
	for v := range resuChan {
		num += v
	}
	return num
}

// 关闭结果通道
func closeResultChan(resuChan chan<- int, done chan struct{}, worksNum int) {
	// 这里我们取出计算完的结果， 因为前面开启的了worksNum个goroutine，所以这里循环多少次
	// 循环完就代表计算完了
	for i := 0; i < worksNum; i++ {
		<-done
	}
	defer close(done)
	defer close(resuChan)
}
